using System;
using System.Linq;
using Linquid;

namespace LinquidSamples
{	
	public class Calculator
	{				
		private static UI<Source<char>> ButtonRow(string buttonNames)
		{
			return (from c in buttonNames
				 	select from click in UIM.Button(c.ToString())
				 		   select click.Const(c)).Concat().FromLeft();
		}								
			
		private static UI<Source<char>> ButtonTable(string buttonNames)
		{
			return (from names in buttonNames.Split(' ')
			        select ButtonRow(names)).Concat();
		}	
		
		private static UI<Source<A>> Result<A>(Source<A> source)
		{
			return from _ in UIM.Output(source)
				   group source by "Result";
		}
		
		private static Func<int, int> Operation(char name, int i)
		{
			switch (name)
			{
				case '+': return n => i + n;
				case '-': return n => i - n;
				case '*': return n => i * n;
				case '/': return n => i / n;				
				default: return n => n;
			}			
		}
						
		private static Pair<int, Func<int, int>> Compute(char c, Pair<int, Func<int, int>> pair)
		{					
			var i = pair.First;
			var f = pair.Second;
			if (char.IsDigit(c))			
				return new Pair<int, Func<int, int>>(i * 10 + int.Parse(c.ToString()), f);
			else if (c == '=')
				return new Pair<int, Func<int, int>>(f(i), n => f(i));
			else			
				return new Pair<int, Func<int, int>>(0, Operation(c, f(i)));
		}
						
		private static UI<Source<int>> Create()
		{
			return from chars in ButtonTable("123+ 456- 789* C0=/")
				   let state = chars.Fold(Compute, new Pair<int, Func<int, int>>(0, i => i))
				   let i = state.Map(p => p.First)
				   from _ in Result(i)
				   group i by "Calculator";
		}
		
		public static UI<Source<int>> UI = Create();
	}
}
